package com.newtouch.bxzs.business.message.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.newtouch.bxzs.business.enclosure.mapper.AttachmentMapper;
import com.newtouch.bxzs.business.enclosure.service.AttachmentService;
import com.newtouch.bxzs.business.message.controller.AdvertisementController;
import com.newtouch.bxzs.business.message.mapper.AdvertisementMapper;
import com.newtouch.bxzs.business.message.model.*;
import com.newtouch.bxzs.business.message.service.AdvertisementService;
import com.newtouch.bxzs.business.message.service.AnnouncementService;
import com.newtouch.bxzs.business.product.mapper.UserMapper;
import com.newtouch.bxzs.common.base.BaseErrorEnum;
import com.newtouch.bxzs.common.base.BaseException;
import com.newtouch.bxzs.common.base.em.AdvertisementTypeEnum;
import com.newtouch.bxzs.common.base.em.ButtonTypeEnum;
import com.newtouch.bxzs.common.base.em.PublishStatusEnum;
import com.newtouch.bxzs.common.base.em.SystemParamsEnum;
import com.newtouch.bxzs.common.base.model.Advertisement;
import com.newtouch.bxzs.common.base.model.Attachment;
import com.newtouch.bxzs.common.base.model.User;
import com.newtouch.bxzs.common.base.model.vo.EnclosureVO;
import com.newtouch.bxzs.common.base.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 广告的serviceImpl类
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2020/12/18 14:23</td>
 * <td>liman</td>
 * <td>Create</td>
 * </tr>
 * </table>
 *
 * @author liman
 * @version 1.0.0
 * @since 1.0.0
 */
@Service
public class AdvertisementServiceImpl implements AdvertisementService {

    @Resource
    private AdvertisementMapper advertisementMapper;

    @Resource
    private AttachmentMapper attachmentMapper;

    @Autowired
    private AttachmentService attachmentService;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private AnnouncementService announcementService;

    /**
     * 静态变量：系统日志
     */
    private static final Log logger = LogFactory.getLog(AdvertisementController.class);

    /**
     * 已发布状态常量
     */
    private static final String PUBLIC_STATUS = PublishStatusEnum.PUBLISHED_STATUS.getResultCode();

    /**
     * 首页类型常量
     */
    private static final String HOME_ADVERTISEMENT = AdvertisementTypeEnum.HOME_ADVERTISEMENT.getCode();

    /**
     * 传入参数的效验异常
     */
    private static final BaseErrorEnum REQUEST_DATA_NULL = BaseErrorEnum.REQUEST_DATA_NULL;

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * getAdvertisementList(com.newtouch.bxzs.message.model.AdvertisementVO)
     */
    @Override
    public IPage<AdvertisementBO> getAdvertisementList(AdvertisementVO advertisementVO) {
        return getList(advertisementVO);
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * getAdvertisement()
     */
    @Override
    public AdvertisementBO getAdvertisement() {
        /* 指定数据 */
        AdvertisementVO advertisementVO = new AdvertisementVO();
        /* 启动页广告 */
        advertisementVO.setAdvertisementType(AdvertisementTypeEnum.START_ADVERTISEMENT.getCode());
        /* 首页广告 */
        advertisementVO.setPublishStatus(PublishStatusEnum.PUBLISHED_STATUS.getResultCode());
        advertisementVO.setCurrentPage(1);
        advertisementVO.setPageSize(99);
        List<AdvertisementBO> list = Objects.requireNonNull(getList(advertisementVO)).getRecords();
        Assert.notEmpty(list, BaseErrorEnum.NOT_FOUND.getResultMsg());
        return RandomUtil.randomEle(list);
    }

    private IPage<AdvertisementBO> getList(AdvertisementVO advertisementVO) {
        if (StringUtils.isEmpty(advertisementVO.getAdvertisementType())) {
            throw new BaseException(BaseErrorEnum.REQUEST_DATA_NULL);
        }
        boolean condition = BeanUtil.isEmpty(advertisementVO) || StringUtils.isEmpty(advertisementVO.getPageSize())
                || StringUtils.isEmpty(advertisementVO.getCurrentPage())
                || !advertisementVO.getAdvertisementType().equals(HOME_ADVERTISEMENT) && !advertisementVO
                .getAdvertisementType().equals(AdvertisementTypeEnum.START_ADVERTISEMENT.getCode());
        if (condition) {
            throw new BaseException(REQUEST_DATA_NULL);
        }
        if (!StringUtils.isEmpty(advertisementVO.getPublishStatus())) {
            if (!advertisementVO.getPublishStatus().equals(PublishStatusEnum.PUBLISHED_STATUS.getResultCode())
                    && !advertisementVO.getPublishStatus().equals(PublishStatusEnum.REVOKED_STATUS.getResultCode())
                    && !advertisementVO.getPublishStatus().equals(PublishStatusEnum.END_STATUS.getResultCode())
                    && !advertisementVO.getPublishStatus().equals(PublishStatusEnum.UNPUBLISH_STATUS.getResultCode())) {
                throw new BaseException(REQUEST_DATA_NULL);
            }
        }
        /* 实例化一个QueryWrapper */
        QueryWrapper<Advertisement> query = new QueryWrapper<>();
        /* 判断是启动页还是首页广告 */
        if (!StringUtils.isEmpty(advertisementVO.getAdvertisementType())) {
            query.eq("ADVERTISEMENT_TYPE", advertisementVO.getAdvertisementType());
        }
        /* 判断是否传入广告名称查询条件 */
        if (!StringUtils.isEmpty(advertisementVO.getAdvertisementName())) {
            query.like("ADVERTISEMENT_NAME", advertisementVO.getAdvertisementName());
        }
        /* 判断是否传入广告状态查询条件 */
        if (!StringUtils.isEmpty(advertisementVO.getPublishStatus())) {
            query.eq("PUBLISH_STATUS", advertisementVO.getPublishStatus());
        }
        /* 选择排序方式(按创建时间倒序排序) */
        query.orderByDesc("CREATE_TIME");
        /* 分页 */
        Page<Advertisement> p = new Page<>(advertisementVO.getCurrentPage(), advertisementVO.getPageSize());
        IPage<Advertisement> advertisements = advertisementMapper.selectPage(p, query);
        if (advertisements == null) {
            return null;
        }
        List<AdvertisementBO> boList = EntityToBeanUtils.copyBean(advertisements.getRecords(), AdvertisementBO.class);
        /* 根据广告id集合查询附件集合 */
        QueryWrapper<Attachment> query2 = new QueryWrapper<>();
        List<String> collect = advertisements.getRecords().stream().map(Advertisement::getAdvertisementId)
                .collect(Collectors.toList());
        /* 包装附件 */
        getAttachmentListByAdvertisementId(boList, query2, collect);
        IPage<AdvertisementBO> advertisementBOList = new Page<>();
        /* 将转换的BO放到advertisementBOList的Records */
        advertisementBOList.setRecords(boList);
        advertisementBOList.setCurrent(advertisements.getCurrent());
        advertisementBOList.setPages(advertisements.getPages());
        advertisementBOList.setSize(advertisements.getSize());
        advertisementBOList.setTotal(advertisements.getTotal());
        return advertisementBOList;
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * getAdvertisementListOnApp()
     */
    @Override
    public List<AdvertisementBO> getAdvertisementListOnApp() {
        QueryWrapper<Advertisement> query = new QueryWrapper<>();
        /* 发布状态 */
        query.eq("PUBLISH_STATUS", PublishStatusEnum.PUBLISHED_STATUS.getResultCode());
        /* 首页广告 */
        query.eq("ADVERTISEMENT_TYPE", AdvertisementTypeEnum.HOME_ADVERTISEMENT.getCode());
        List<Advertisement> advertisementList = advertisementMapper.selectList(query);
        /* 转换类型 */
        List<AdvertisementBO> list = EntityToBeanUtils.copyBean(advertisementMapper.selectList(query),
                AdvertisementBO.class);
        /* 首页广告，设置每张首页广告展示2秒(可配置）,时间从缓存中获取 */
        Integer maxHomeAdvertisementTime = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.INDEX_ADVERTISEMENT_SHOW_TIME.getCode()));
        for (AdvertisementBO advertisementBO : list) {
            advertisementBO.setLimitTime(maxHomeAdvertisementTime);
        }
        /* 根据广告id集合查询附件集合 */
        QueryWrapper<Attachment> query2 = new QueryWrapper<>();
        List<String> collect = advertisementList.stream().map(Advertisement::getAdvertisementId)
                .collect(Collectors.toList());
        /* 包装附件 */
        getAttachmentListByAdvertisementId(list, query2, collect);
        return list;
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * getAdvertisementDetail(java.lang.String)
     */
    @Override
    public AdvertisementDetailBO getAdvertisementDetail(String advertisementId) {
        if (StringUtils.isEmpty(advertisementId)) {
            logger.info("查看详情失败");
            throw new BaseException(BaseErrorEnum.REQUEST_DATA_NULL);
        }
        Advertisement advertisement = advertisementMapper.selectById(advertisementId);
        if (advertisement == null) {
            return null;
        }
        AdvertisementDetailBO advertisementDetailBO = new AdvertisementDetailBO();
        /* 使用工具直接进行实体与BO的复制转换，注意字段名及类型需保持一致 */
        BeanUtil.copyProperties(advertisement, advertisementDetailBO);
        /* 首页广告，设置每张首页广告展示2秒(可配置）,时间从缓存中获取 */
        Integer maxHomeAdvertisementTime = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.INDEX_ADVERTISEMENT_SHOW_TIME.getCode()));
        if (Objects.equals(advertisementDetailBO.getAdvertisementType(), HOME_ADVERTISEMENT)) {
            advertisementDetailBO.setLimitTime(maxHomeAdvertisementTime);
        }
        /* 获取附件 */
        HashMap<String, List<String>> result = attachmentService
                .getEnclosureList(new EnclosureVO(advertisementId, null));
        if (result != null) {
            advertisementDetailBO.setAttachmentUrls(result);
        }
        /* 获取操作人 */
        User user = userMapper.selectById(advertisement.getUpdateUserId());
        if (!BeanUtil.isEmpty(user)) {
            advertisementDetailBO.setOperationUser(user.getUserName());
        }
        return advertisementDetailBO;
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * deleteAdvertisement(java.util.List)
     */
    @Override
    public Integer deleteAdvertisement(List<String> advertisementIds) {
        if (CollectionUtil.isEmpty(advertisementIds)) {
            logger.info("删除失败");
            throw new BaseException(BaseErrorEnum.REQUEST_DATA_NULL);
        }
        QueryWrapper<Advertisement> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("ADVERTISEMENT_ID", advertisementIds);
        queryWrapper.eq("PUBLISH_STATUS", PUBLIC_STATUS);
        List<Advertisement> advertisements = advertisementMapper.selectList(queryWrapper);
        if (!CollectionUtil.isEmpty(advertisements)) {
            logger.info("删除失败");
            throw new BaseException(BaseErrorEnum.PUBLISH_STATUS);
        }
        /* 设置修改人状态和修改时间 */
        QueryWrapper<Advertisement> updateQuery = new QueryWrapper<>();
        updateQuery.in("ADVERTISEMENT_ID", advertisementIds);
        Advertisement advertisement = new Advertisement();
        advertisement.setUpdateTime(new Date());
        advertisement.setUpdateUserId(Objects.requireNonNull(UserDetailUtil.getUserDetail()).getUserId());
        advertisementMapper.update(advertisement, updateQuery);
        /* 批量逻辑删除广告 */
        if (advertisementMapper.deleteBatchIds(advertisementIds) > 0) {
            /* 批量删除附件信息 */
            attachmentMapper.delete(new QueryWrapper<Attachment>().in("ATTACHMENT_RELATION_ID", advertisementIds));
        }
        return null;
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * modifyAdvertisement(com.newtouch.bxzs.message.model.
     * modifyAdvertisementVO)
     */
    @Override
    public String modifyAdvertisement(ModifyAdvertisementVO modifyAdvertisementVO) {
        /* 判断传入数据是否合格 */
        if (modifyAdvertisementVO == null) {
            logger.info("新增或修改失败");
            throw new BaseException(REQUEST_DATA_NULL);
        }
        boolean condition = !Objects.equals(modifyAdvertisementVO.getButtonType(),
                ButtonTypeEnum.TEMPORARY_BUTTON.getCode())
                && !Objects.equals(modifyAdvertisementVO.getButtonType(), ButtonTypeEnum.PUBLIC_BUTTON.getCode())
                || StringUtils.isEmpty(modifyAdvertisementVO.getAdvertisementName());
        if (condition) {
            logger.info("新增或修改失败");
            throw new BaseException(REQUEST_DATA_NULL);
        }
        /* 效验网址格式（http/https） */
        if (modifyAdvertisementVO.getAdvertisementUrl() != null
                && !StringUtils.isEmpty(modifyAdvertisementVO.getAdvertisementUrl())) {
            String str = "^(product\\/detail\\?id\\=)[a-zA-Z0-9]+$";
            if (!modifyAdvertisementVO.getAdvertisementUrl().matches(str)) {
                logger.info("新增或修改失败");
                throw new BaseException("-1", "输入的网址格式有误");
            }
        }
        /*从缓存中获取配置的广告的发布时间的最大限制和配置的广告的撤销时间的最大限制  */
        Integer maxPublishTime = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.MAX_PUBLISH_DAY_LIMIT.getCode()));
        String maxRevokeTime = announcementService.getParameterValueRedis(SystemParamsEnum.MAX_REVOKE_DATE_LIMIT.getCode());
        CheckPublishDateUtils.checkDate(modifyAdvertisementVO.getPublishTime(),
                modifyAdvertisementVO.getRevokeTime(), maxPublishTime, maxRevokeTime);
        Advertisement advertisement = new Advertisement();
        /* 使用工具直接进行实体与BO的复制转换，注意字段名及类型需保持一致 */
        BeanUtil.copyProperties(modifyAdvertisementVO, advertisement);
        /* 根据vo传入的按钮类型，判断是发布还是暂存（buttonType（1：暂存，2：发布，3：撤销）） */
        /* 先默认未发布状态 */
        advertisement.setPublishStatus(PublishStatusEnum.UNPUBLISH_STATUS.getResultCode());
        if (Objects.equals(modifyAdvertisementVO.getButtonType(), ButtonTypeEnum.PUBLIC_BUTTON.getCode())) {
            /*
             * 是发布按钮，效验发布状态是广告是否已达上限，跟publishAdvertNumber（publishAdvertNumber=
             * 5可配置，设置的上限数值）作比较
             */
            QueryWrapper<Advertisement> query = new QueryWrapper<>();
            query.eq("PUBLISH_STATUS", PUBLIC_STATUS);
            query.eq("ADVERTISEMENT_TYPE", modifyAdvertisementVO.getAdvertisementType());
            /* 从缓存获取广告最大发布数量 */
            Integer maxNumber;
            if (Objects.equals(modifyAdvertisementVO.getAdvertisementType(), AdvertisementTypeEnum.START_ADVERTISEMENT.getCode())) {
                maxNumber = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.START_ADVERTISEMENT_LIMIT_NUMBER.getCode()));
            } else if (Objects.equals(modifyAdvertisementVO.getAdvertisementType(), AdvertisementTypeEnum.HOME_ADVERTISEMENT.getCode())) {
                maxNumber = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.INDEX_ADVERTISEMENT_LIMIT_NUMBER.getCode()));
            } else {
                logger.info("类型错误");
                throw new BaseException(BaseErrorEnum.REQUEST_PARAMETER_ERROR.getResultCode(), BaseErrorEnum.REQUEST_PARAMETER_ERROR.getResultMsg() + "广告类型错误");
            }
            if (advertisementMapper.selectCount(query) >= maxNumber) {
                /* 已达上限 */
                logger.info("发布失败,已达上限");
                throw new BaseException(BaseErrorEnum.PUBLISH_OVER_LIMIT);
            }
            advertisement.setPublishTime(new Date());
            /* 设置广告状态是已发布状态 */
            advertisement.setPublishStatus(PUBLIC_STATUS);
        }
        if (StringUtils.isEmpty(modifyAdvertisementVO.getAdvertisementId())) {
            /* 新增广告 */
            logger.info("新增广告");
            advertisement.setCreateUserId(Objects.requireNonNull(UserDetailUtil.getUserDetail()).getUserId());
            /* 设置创建人id */
            advertisement.setCreateTime(new Date());
            /* 设置创建时间 */
            advertisement.setUpdateUserId(Objects.requireNonNull(UserDetailUtil.getUserDetail().getUserId()));
            /* 设置修改人id */
            advertisement.setUpdateTime(new Date());
            /* 设置修改时间 */
            advertisementMapper.insert(advertisement);
        } else {
            /*
             * 修改 若是发布状态或者id为空
             */
            if (Objects.equals(
                    advertisementMapper.selectById(modifyAdvertisementVO.getAdvertisementId()).getPublishStatus(),
                    PUBLIC_STATUS)) {
                logger.info("修改失败");
                throw new BaseException(BaseErrorEnum.PUBLISH_STATUS);
            }
            logger.info("修改广告");
            /* 设置修改人id */
            advertisement.setUpdateUserId(Objects.requireNonNull(UserDetailUtil.getUserDetail()).getUserId());
            /* 设置修改时间 */
            advertisement.setUpdateTime(new Date());
            advertisementMapper.updateById(advertisement);
        }
        return advertisement.getAdvertisementId();
    }

    /**
     * (non-Javadoc)
     * <p>
     * com.newtouch.bxzs.message.service.AdvertisementService#
     * changeAdvertisementState(com.newtouch.bxzs.message.model.ChangeStatusVO)
     */
    @Override
    public Integer changeAdvertisementState(ChangeStatusVO changeStatusVO) {
        if (changeStatusVO == null) {
            logger.info("修改状态失败");
            throw new BaseException(REQUEST_DATA_NULL);
        }
        if (StringUtils.isEmpty(changeStatusVO.getAdvertisementId())
                && StringUtils.isEmpty(changeStatusVO.getButtonType())
                && !Objects.equals(changeStatusVO.getButtonType(), ButtonTypeEnum.PUBLIC_BUTTON.getCode())
                && !Objects.equals(changeStatusVO.getButtonType(), ButtonTypeEnum.REVOKE_BUTTON.getCode())) {
            return null;
        }
        Advertisement advertisement = new Advertisement();
        QueryWrapper<Advertisement> updateQuery = new QueryWrapper<>();
        if (Objects.equals(changeStatusVO.getButtonType(), ButtonTypeEnum.PUBLIC_BUTTON.getCode())) {
            /*
             * 点击的发布按钮，效验发布状态是广告是否已达上限，跟publishAdvertNumber（publishAdvertNumber=
             * 5可配置，设置的上限数值）作比较
             */
            QueryWrapper<Advertisement> query = new QueryWrapper<>();
            query.eq("PUBLISH_STATUS", PUBLIC_STATUS);
            query.eq("ADVERTISEMENT_TYPE", changeStatusVO.getAdvertisementType());
            /* 已达上限 */
            /* 从缓存获取广告最大发布数量 */
            Integer maxNumber;
            if (Objects.equals(changeStatusVO.getAdvertisementType(), AdvertisementTypeEnum.START_ADVERTISEMENT.getCode())) {
                maxNumber = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.START_ADVERTISEMENT_LIMIT_NUMBER.getCode()));
            } else if (Objects.equals(changeStatusVO.getAdvertisementType(), AdvertisementTypeEnum.HOME_ADVERTISEMENT.getCode())) {
                maxNumber = Integer.parseInt(announcementService.getParameterValueRedis(SystemParamsEnum.INDEX_ADVERTISEMENT_LIMIT_NUMBER.getCode()));
            } else {
                logger.info("类型错误");
                throw new BaseException(BaseErrorEnum.REQUEST_PARAMETER_ERROR.getResultCode(), BaseErrorEnum.REQUEST_PARAMETER_ERROR.getResultMsg() + "广告类型错误");
            }
            if (advertisementMapper.selectCount(query) >= maxNumber) {
                logger.info("发布失败");
                throw new BaseException(BaseErrorEnum.PUBLISH_OVER_LIMIT);
            }
            advertisement.setPublishStatus(PUBLIC_STATUS);
            advertisement.setPublishTime(new Date());
        } else {
            /* 点击的撤销按钮 */
            advertisement.setPublishStatus(PublishStatusEnum.REVOKED_STATUS.getResultCode());
            advertisement.setRevokeTime(new Date());
        }
        /* 设置修改时间和修改人 */
        advertisement.setUpdateTime(new Date());
        advertisement.setUpdateUserId(Objects.requireNonNull(UserDetailUtil.getUserDetail()).getUserId());
        updateQuery.eq("ADVERTISEMENT_ID", changeStatusVO.getAdvertisementId());
        return advertisementMapper.update(advertisement, updateQuery);
    }

    /**
     * 根据广告id集合查询附件集合
     *
     * @param list    AdvertisementBO集合
     * @param query2  query条件
     * @param collect 广告id集合
     */
    private void getAttachmentListByAdvertisementId(List<AdvertisementBO> list, QueryWrapper<Attachment> query2,
                                                    List<String> collect) {
        if (CollectionUtil.isEmpty(collect)) {
            collect.add("0");
        }
        query2.in("ATTACHMENT_RELATION_ID", collect);
        List<Attachment> attachmentList = attachmentMapper.selectList(query2);
        if (!CollectionUtil.isEmpty(attachmentList)) {
            for (AdvertisementBO advertisementBO : list) {
                for (Attachment attachment : attachmentList) {
                    if (Objects.equals(attachment.getAttachmentRelationId(), advertisementBO.getAdvertisementId())) {
                        advertisementBO.setAttachmentUrls(
                                attachment.getAttachmentUrl() + "/" + attachment.getAttachmentName());
                    }
                }
            }
        }
    }

}
